/*

num2strtab  - creates a tabular data output of a numeric data table

FORMAT:       asc = num2strtab(n [, d [, nd [, ld]]])

Input fields:

      n           numeric array
      d           number of digits
      nd          delimiter between individual numbers/columns
      ld          line/row delimiter

Output fields:

      asc         ASCII representation of table

% Version:  v0.7f
% Build:    8110521
% Date:     Nov-05 2008, 9:00 PM CET
% Author:   Jochen Weber, SCAN Unit, Columbia University, NYC, NY, USA
% URL/Info: http://wiki.brainvoyager.com/BVQXtools

*/

#include "mex.h"
#include "matrix.h"
#include "math.h"

#define CONVERTDBL2NUM \
    dval = input[rc + cc * rdim]; \
    if (dval < 0) { \
        *asc++ = 45; \
        dval = -dval; \
    } else if (forcesign) \
        *asc++ = 43; \
    else \
        *asc++ = 32; \
    lval = (int) log10(dval); \
    dval /= exp(e10 * ((double) lval)); \
    idval = (int) dval; \
    if (idval > 9) { \
        idval = 1; \
        dval /= 10.0; \
        ++lval; \
    } \
    *asc++ = ascdigits[idval]; \
    *asc++ = 46; \
    for (dc = numdigits; dc > 0; --dc) { \
        dval = (dval - (double) idval) * 10.0; \
        idval = (int) dval; \
        if (idval > 9) \
            idval = 9; \
        *asc++ = ascdigits[idval]; \
        if (dval == 0.0) \
            break; \
    } \
    *asc++ = 101; \
    if (lval < 0) { \
        lval = -lval; \
        *asc++ = 45; \
    } else \
        *asc++ = 43; \
    if (lval >= 100) { \
        idval = (int) (((double) lval) / 100.0); \
        *asc++ = ascdigits[idval]; \
        lval -= idval * 100; \
    } else \
        *asc++ = 48; \
    if (lval >= 10) { \
        idval = (int) (((double) lval) / 10.0); \
        *asc++ = ascdigits[idval]; \
        lval -= idval * 10; \
    } else \
        *asc++ = 48; \
    *asc++ = ascdigits[lval]; \
    for (; dc > 0; --dc) \
        *asc++ = 32;

const unsigned short ascdigits[11] = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 63};

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
    int ne, rdim, cdim, rc, cc, idval, lval;
    const int *dim;
    int odim[2] = {1, 0};
    double dval, e10;
    
    const double *input;
    unsigned short *asc;
    const unsigned short defcoldelim[1] = {9};
    const unsigned short deflinedelim[1] = {10};
    const unsigned short *coldelim, *linedelim;
    unsigned short coldelv, linedelv;
    signed char coldellen = 1, linedellen = 1;
    
    signed char numdigits = 8, colwidth = 16, dc = 0; 
    bool forcesign = false, forcefp = false;
    
	if (nrhs < 1 || nrhs > 4 || nlhs > 1)
		mexErrMsgTxt("Bad number of input/output arguments.");
    
    if (mxGetClassID(*prhs) != mxDOUBLE_CLASS)
        mexErrMsgTxt("Numerical data must be double.");

    if (mxGetNumberOfDimensions(*prhs) != 2)
        mexErrMsgTxt("Input must be a MxN matrix.");

    dim = mxGetDimensions(*prhs);
    if ((*dim == 0) && (dim[1] == 0)) {
        *odim = 0;
        *plhs = mxCreateCharArray(2, odim);
        return;
    }
    input = (const double *) mxGetData(*prhs);
    coldelim = defcoldelim;
    linedelim = deflinedelim;
    
    if (nrhs > 1) {
    }
    
    ne = (int) ((double) *dim) * ((double) (linedellen - coldellen) + ((double) dim[1]) * ((double) (coldellen + colwidth)));
    odim[1] = ne;
    *plhs = mxCreateCharArray(2, odim);
    asc = (unsigned short *) mxGetData(*plhs);
    e10 = log(10.0);
    
    rdim = *dim;
    cdim = dim[1];
    if (coldellen == 1) {
        coldelv = *coldelim;
        for (rc = 0; rc < rdim; ++rc) {
            for (cc = 0; cc < cdim; ++cc) {
                CONVERTDBL2NUM
                *asc++ = coldelv;
            }
            --asc;
            for (dc = 0; dc < linedellen; ++dc)
                *asc++ = linedelim[dc];
        }
    } else {
        for (rc = 0; rc < rdim; ++rc) {
            for (cc = 0; cc < cdim; ++cc) {
                CONVERTDBL2NUM
            }
        }
    }
}
